#include "Matrix3.h"
#include "SpotLight.h"

SpotLight::SpotLight()
:
m_direction( -Vector3::UNIT_Z )
{
	set_angle( Math::PI );
	m_exponent = 0.0;
}

void SpotLight::set_angle( Real angle )
{
	m_angle = angle;
	m_cos_sqr = Math::cos_t( m_angle );
	m_cos_sqr *= m_cos_sqr;
	m_sin_sqr = Math::sin_t( m_angle );
	m_sin_sqr *= m_sin_sqr;
}

void SpotLight::compute_diffuse( const Matrix3& world_rotate, const Vector3& world_translate,
								Real world_scale, const Vector3* vertex, const Vector3* normal,
								unsigned int num_spot_lights, const bool* visible, Color* diffuse )
{
	//transform light position to model space of old mesh
	Real inv_scale = 1.0 / world_scale;
	Vector3 diff = m_location - world_translate;
	Vector3 model_pos = ( diff * world_rotate ) * inv_scale;
	Vector3 model_dir = m_direction * world_rotate;

	// adjust diffuse color by light intensity
	Color adj_diffuse = m_intensity * m_diffuse;

	for ( unsigned int i = 0; i < num_spot_lights; i++ )
	{
		if ( visible[i] )
		{
			diff = model_pos - vertex[i];
			Real diff_dot_dir = diff.dot( model_dir );
			if ( diff_dot_dir >= 0.0 )
				continue;

			Real len_sqr = diff.dot( diff );
			Real diff_dot_dir_sqr = diff_dot_dir * diff_dot_dir;
			Real angle_attenuate = diff_dot_dir_sqr - len_sqr * m_cos_sqr;
			if ( angle_attenuate <= 0.0 )
				continue;

			Real dot = diff.dot( normal[i] );
			if ( dot > 0.0 )
			{
				Real numer = dot * angle_attenuate;
				Real denom = diff_dot_dir_sqr * m_sin_sqr * Math::sqrt_t( len_sqr );
				diffuse[i] += (numer/denom)*adj_diffuse;
			}
		}
	}
}

void SpotLight::compute_specular( const Matrix3& world_translate, const Vector3& world_translate,
								 Real world_scale, const Vector3* vertex, const Vector3* normal,
								 unsigned int num_spot_lights, const bool* visible, const Vector3& camera_model_location,
								 Color* specular )
{
	// transform light position to model space of old mesh
	Real inv_scale = 1.0 / world_scale;
	Vector3 diff = m_location - world_translate;
	Vector3 model_pos = ( diff * world_rotate ) * inv_scale;
	Vector3 model_dir = m_direction * world_rotate;

	// adjust specular color by light intensity
	Color adj_specular = m_intensity * m_specular;

	for ( unsigned int i = 0; i < num_spot_lights; i++ )
	{
		if ( visible[i] )
		{
			diff = model_pos - vertex[i];
			Real diff_dot_dir = diff.dot(model_dir);
			if ( diff_dot_dir >= 0.0 )
				continue;

			Real len_sqr = diff.dot( diff );
			Real diff_dot_dir_sqr = diff_dot_dir * diff_dot_dir;
			Real angle_attenuate = diff_dot_dir_sqr - len_sqr * m_cos_sqr;
			if ( angle_attenuate <= 0.0 )
				continue;

			Real dot = diff.dot( normal[i] );
			Vector3 reflect = (2.0*dot) * normal[i] - diff;
			Vector3 viewdir = camera_model_location - vertex[i];
			dot = viewdir.dot( reflect );

			if ( dot > 0.0 )
			{
				Real numer = dot * dot * angle_attenuate;
				Real denom = diff_dot_dir_sqr * m_sin_sqr * 
					Math::sqrt_t( len_sqr ) * viewdir.dot(viewdir);
				specular[i] += (numer/denom)*adj_specular;
			}
		}
	}
}



